<?php

define ( 'ROUTE_METHOD_REDIRECT', 'ROUTE_METHOD_REDIRECT' );
define ( 'ROUTE_METHOD_AUTH', 'ROUTE_METHOD_AUTH' );

class Route {
	
	private $param;
	private $config_route;
	//Base Path
	private $basepath;
	//Uri path
	private $uri;
	//File name
	private $filename;
	
	const SYMBOL_SPLIT = ':';
	const SYMBOL_PATH_SPLIT = '/'; //Get variable prefix from sub
	const SYMBOL_PARAM_SPLIT = '-'; //Regular pattern prefix in sub
	const PATTERN_SUFFIX = '$'; //Regular pattern suffix in sub
	

	public function __construct($config_route = array()) {
		if (DEBUG === TRUE) {
			echo '--- Route construct!' . '<br/>';
		}
		$this->config_route = $config_route;
		$this->doUri ();
		$this->parseRoute ();
	}
	
	/**
	 * Set uri string to object
	 * 
	 */
	public function doUri() {
		$script_name = $this->os_lower ( $_SERVER ['SCRIPT_NAME'] );
		$filename = $this->filename = substr ( strrchr ( $script_name, '/' ), 1 );
		if (! defined ( 'BASE_PATH' )) {
			define ( 'BASE_PATH', str_replace ( $filename, '', $script_name ) );
		}
		$basepath = $this->basepath = $this->os_lower ( BASE_PATH );
		$temp = explode ( "?", $this->os_lower ( $_SERVER ["REQUEST_URI"] ) );
		$requesturi = $temp [0];
		$length_scriptname = strlen ( $script_name );
		$uristring = $requesturi;
		if (substr ( $requesturi, 0, $length_scriptname ) == $script_name) {
			$uristring = substr ( $requesturi, $length_scriptname );
		}
		$this->uri = str_replace ( $basepath, '/', $uristring );
		if ($this->uri == '')
			$this->uri = '/';
		if (DEBUG === TRUE) {
			echo '<h3>Route Info:</h3>';
			echo ' base:' . $this->basepath . '<br />';
			echo ' file:' . $this->filename . '<br />';
			echo ' uri:' . $this->uri . '<br />';
		}
	}
	
	private function os_lower($str) {
		if (strtolower ( PHP_OS ) == 'linux') {
			return $str;
		} else {
			return strtolower ( $str );
		}
	}
	
	/**
	 * Routing 
	 * 
	 */
	public function parseRoute() {
		$route = $this->config_route;
		if ($this->uri == '/' && (isset ( $_GET ['module'] ) || isset ( $_GET ['action'] )) && strpos ( $_SERVER ["REQUEST_URI"], '?' ) !== false) {
			$this->param ['module'] = $_GET ['module'];
			$this->param ['action'] = $_GET ['action'];
		} else {
			//open regular route
			$regular = false;
			if (ROUTE_ON === TRUE && ! empty ( $route )) {
				$regular = $this->parseUri ( $this->uri );
			}
			//if not routed, use default route
			if (! $regular) {
				$param = explode ( "/", $this->uri );
				//print_r($param);
				$this->param ['module'] = $param [1];
				$this->param ['action'] = isset ( $param [2] ) ? $param [2] : '';
				if (count ( $param ) > 3) {
					for($i = 3; $i < count ( $param ); $i += 2) {
						if ($param [$i] != '') {
							$this->param [$param [$i]] = isset ( $param [$i + 1] ) ? $param [$i + 1] : '';
						}
					}
				}
			}
		}
		$this->applyParam ();
	}
	
	/**
	 * Apply value as param to $_GET
	 * 
	 */
	public function applyParam() {
		//print_r($this->param);
		foreach ( $this->param as $key => $value ) {
			@$_GET [$key] = $value;
		}
	}
	
	/**
	 * Parse Uri String
	 * 
	 * @param $uri uri string
	 * @return bool parse status
	 */
	public function parseUri($uri) {
		$method = strtolower ( $_SERVER ['REQUEST_METHOD'] );
		$route = $this->config_route;
		
		if (isset ( $route [$method] )) {
			$approute = $route [$method];
		}
		
		if (isset ( $route ['*'] )) {
			if (isset ( $approute ))
				$approute = array_merge ( $approute, $route ['*'] );
			else
				$approute = $route ['*'];
		}
		//精度匹配
		$value = NULL;
		if (isset ( $route ['*'] [$uri] ) && ! empty ( $route ['*'] [$uri] )) {
			$value = $route ['*'] [$uri];
		}
		
		if ($value != NULL) {
			$this->parseValue ( $value );
			return true;
		} else {
			if (substr ( $uri, 0, 1 ) != '/') {
				$uri = '/' . str_replace ( ':', '/', $route ['/'] ) . $uri;
			}
			//$uri = substr ( $uri, 1 );
			$uri_unit = explode ( '/', $uri );
			
			foreach ( $approute as $key => $value ) {
				$key = '/^' . str_replace ( '/', '\/', $key ) . '/';
				$matches = array ();
				if (@preg_match ( $key, $uri, $matches )) {
					$this->parseValue ( $value, $matches );
					return true;
				}
			}
		}
		return false;
	}
	
	/**
	 * Parse valuse to param
	 * 
	 * @param $str value string
	 * @param $matches match array 
	 */
	private function parseValue($str, $matches = NULL) {
		$value = array ();
		$path_str = $param_str = $controller = $action = NULL;
		@list ( $path_str, $param_str ) = explode ( self::SYMBOL_SPLIT, $str );
		@list ( $controller, $action ) = explode ( self::SYMBOL_PATH_SPLIT, $path_str );
		$this->param ['controller'] = $controller;
		$this->param ['action'] = $action;
		if ($param_str && ! empty ( $matches )) {
			$params = explode ( self::SYMBOL_PARAM_SPLIT, $param_str );
			unset ( $matches [0] );
			foreach ( $matches as $k => $v ) {
				$this->param [$params [$k - 1]] = $v;
			}
		}
	}

}
?>